#include "window.h"
#include "teflon/core/events.h"

namespace teflon
{
    void glfw_error_callback(int error, const char* description)
    {
        fputs(description, stderr);
    }

    void glfw_frame_size_callback(GLFWwindow* window, int width, int height)
    {
        glViewport(0, 0, width, height);
    }

    void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
    {
        auto w = glfwGetWindowUserPointer(window);

        Event evt;
        evt.context.data.u32[0] = (uint32_t)key;
        evt.handled = false;
        if (action == GLFW_PRESS)
        {
            evt.type = EventType::EVENT_KEY_PRESSED;
        }
        else
        {
            evt.type = EventType::EVENT_KEY_RELEASED;
        }

        fire_event(evt, w);
    }

    void glfw_mouse_position_callback(GLFWwindow* window, double xpos, double ypos)
    {
        auto w = glfwGetWindowUserPointer(window);

        Event evt;
        evt.type = EventType::EVENT_MOUSE_MOVE;
        evt.context.data.f32[0] = (float)xpos;
        evt.context.data.f32[1] = (float)ypos;
        evt.handled = false;

        fire_event(evt, w);
    }

    void glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
    {

    }

    void glfw_mouse_scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
    {
        
    }

    Window::Window(const std::string& title, uint32_t width, uint32_t height)
    {
        this->width = width;
        this->height = height;
        this->title = title;

        glfwSetErrorCallback(glfw_error_callback);
        glfwInit();
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
        glfwWindowHint(GLFW_SAMPLES, 4);

        window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
        glfwSetFramebufferSizeCallback(window, glfw_frame_size_callback);
        glfwMakeContextCurrent(window);

        glfwSetWindowUserPointer(window, this);
        glfwSetCursorPosCallback(window, glfw_mouse_position_callback);
        glfwSetKeyCallback(window, glfw_key_callback);

        glewExperimental = GL_TRUE;
        glewInit();

#if 0
        // get version info
        const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
        const GLubyte* version = glGetString(GL_VERSION);  // version as a string
        printf("Renderer: %s\n", renderer);
        printf("OpenGL version supported %s\n", version);
#endif
    }

    Window::Window(const WindowProps& props)
        : Window(props.title, props.width, props.height)
    {
        
    }

    Window::~Window()
    {
        glfwDestroyWindow(window);
        glfwTerminate();
    }

    void Window::ProcessEvents()
    {
        glfwPollEvents();

        // do processing
    }

    void Window::Update()
    {
        glfwSwapBuffers(window);
    }

    bool Window::Closed()
    {
        return glfwWindowShouldClose(window);
    }
}
